<template>
  <div class="login-container">
    <!-- 头部中英文切换 -->
    <div class="absolute top-0 flex items-center justify-end px-5 h-20 w-full">
      <lang-select class="ml-2 cursor-pointer" style="font-size: 18px" />
    </div>
    <!-- 表单 -->
    <el-card
      :device="useAppStore().device"
      class="z-1 !border-none w-100 !bg-transparent !rounded-4% <sm:w-83"
    >
      <el-tabs v-model="active" class="demo-tabs" @tab-click="handleClick">
        <el-tab-pane label="扫码登录" name="qrCode">
          <div class="qrcode-container">
            <img
              :src="qrcode.qrcodeUrl"
              :style="{ opacity: isExpire ? 0.02 : 1 }"
              alt="二维码"
            />
            <div v-show="isExpire">
              <div>二维码已过期</div>
              <div @click="createQrcode">点击刷新</div>
            </div>
          </div>
          <div>微信扫一扫登录</div>
        </el-tab-pane>
        <el-tab-pane label="账号登录" name="user">
          <el-form ref="formRef" :model="form" :rules="rules">
            <el-form-item prop="username">
              <el-input
                v-model="form.username"
                :placeholder="$t('login.username')"
              />
            </el-form-item>
            <el-form-item prop="password">
              <el-input
                v-model="form.password"
                :placeholder="$t('login.password')"
                type="password"
                show-password
                @keyup.enter="handleLogin"
              />
            </el-form-item>
            <el-form-item prop="captchaCode">
              <div class="flex justify-between items-center w-full">
                <el-input
                  style="width: 65%"
                  v-model="form.captchaCode"
                  :placeholder="$t('login.captchaCode')"
                  @keyup.enter="handleLogin"
                />
                <img
                  class="flex-1 h-[40px] cursor-pointer ml-2"
                  :src="captchaBase64"
                  @click="getCaptcha"
                  alt="验证码"
                />
              </div>
            </el-form-item>
            <el-button
              :loading="loading"
              type="primary"
              class="w-full"
              @click.prevent="handleLogin"
            >
              {{ $t("login.login") }}
            </el-button>
          </el-form>
        </el-tab-pane>
      </el-tabs>
      <div class="flex justify-between items-center w-full">
        <div
          class="cursor-pointer register-btn"
          @click="forgotPwdVisible = true"
        >
          忘记密码
        </div>
        <div class="cursor-pointer register-btn" @click="handleRegister">
          没有密码，前往注册
        </div>
      </div>
    </el-card>
    <!-- 小背景 -->
    <div v-show="useAppStore().device === 'desktop'" class="bg-small">
      <div>{{ defaultSettings.title }}</div>
      <img src="../../assets/images/login-bg-small.png" alt="login-bg-small" />
    </div>
    <!-- ICP备案 -->
    <div :class="useAppStore().device">
      Copyright © 2018-2025 Apache 2.0 开源协议.
    </div>
    <!-- 忘记密码 -->
    <forgot-pwd
      v-if="forgotPwdVisible"
      width="400"
      v-model="forgotPwdVisible"
      :title="$t('forgot.forgot')"
      :close-on-click-modal="false"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, watchEffect, computed } from "vue";
import { useWindowSize } from "@vueuse/core";
import { useAppStore } from "@/stores/modules/app";
import { netEncrypt } from "@/utils/netsecret";
import { useUserStore } from "@/stores/modules/user";
import { getCaptchaApi, createLoginQrcode } from "@/api/auth";
import type { LoginData, LoginQrcodeResp } from "@/api/auth/types";

import { useI18n } from "vue-i18n";
import { type FormInstance, type TabsPaneContext } from "element-plus";
import {
  useRoute,
  useRouter,
  type LocationQuery,
  type LocationQueryValue,
} from "vue-router";

import defaultSettings from "@/settings";

import ForgotPwd from "@/components/ForgotPwd/index.vue";
const { t } = useI18n();
// 选项卡切换
const active = ref<string>(vueMetaEnv.APP_ACTIVE as string);
const handleClick = (tab: TabsPaneContext) => {
  if (tab.props.name === "user") {
    handleClearTime();
    getCaptcha();
  } else {
    createQrcode();
  }
  active.value = tab.props.name as string;
};
// 表单
const form = ref<LoginData>({
  scope: "",
  username: "",
  password: "",
});
// 表单校验规则
const rules = computed(() => {
  const prefix = useAppStore().language === "en" ? "Please enter " : "请输入";
  return {
    username: [
      {
        required: true,
        trigger: "blur",
        message: `${prefix}${t("login.username")}`,
      },
    ],
    password: [
      {
        required: true,
        trigger: "blur",
        validator: (rule: any, value: any, callback: any) => {
          if (value.length < 5) {
            callback(new Error("The password can not be less than 5 digits"));
          } else {
            callback();
          }
        },
        message: `${prefix}${t("login.password")}`,
      },
    ],
    captchaCode: [
      {
        required: true,
        trigger: "blur",
        message: `${prefix}${t("login.captchaCode")}`,
      },
    ],
  };
});
// 提交按钮加载
const loading = ref(false);
const formRef = ref<FormInstance>();
// 登录
const route = useRoute();
const router = useRouter();
const userStore = useUserStore();
const handleLogin = () => {
  formRef.value?.validate((valid: boolean) => {
    if (!valid) return;
    loading.value = true;
    userStore
      .login({ ...form.value, password: netEncrypt(form.value.password) })
      .then(() => {
        const query: LocationQuery = route.query;
        const redirect =
          (query.redirect as LocationQueryValue) ?? vueMetaEnv.APP_REDIRECT;
        const otherQueryParams = Object.keys(query).reduce(
          (acc: any, cur: string) => {
            if (cur !== "redirect") {
              acc[cur] = query[cur];
            }
            return acc;
          },
          {},
        );
        router.push({ path: redirect, query: otherQueryParams });
        getCaptcha();
      })
      .catch(() => {
        // 验证失败，重新生成验证码
        getCaptcha();
      })
      .finally(() => {
        loading.value = false;
      });
  });
};

// 获取验证码
const captchaBase64 = ref<string>("");
const getCaptcha = () => {
  getCaptchaApi().then(({ data }) => {
    form.value.captchaKey = data.captchaId;
    captchaBase64.value = data.base64Image;
  });
};
getCaptcha();

let intervalCheck: null | number = setInterval(checkLoginQrcode, 3000);

//二维码
const qrcode = ref<LoginQrcodeResp>({});
// 创建二维码
function createQrcode() {
  createLoginQrcode().then(({ data }) => {
    qrcode.value = data;
    isExpire.value = false;
    handleTimeout();
    //每3秒
    intervalCheck = setInterval(checkLoginQrcode, 3000);
  });
}
active.value === "qrCode" && createQrcode();

// 扫码成功图片
import qrcodesuccess from "../../assets/images/qrcode-success.jpg";
import { vueMetaEnv } from "@/settings";
//扫码登录
function checkLoginQrcode() {
  if (qrcode.value.ticket) {
    userStore.loginByQrcode({ ticket: qrcode.value.ticket }).then(() => {
      handleClearTime();
      isExpire.value = false;
      qrcode.value.qrcodeUrl = qrcodesuccess;
      const query: LocationQuery = route.query;
      const redirect =
        (query.redirect as LocationQueryValue) ?? vueMetaEnv.APP_REDIRECT;
      const otherQueryParams = Object.keys(query).reduce(
        (acc: any, cur: string) => {
          if (cur !== "redirect") {
            acc[cur] = query[cur];
          }
          return acc;
        },
        {},
      );
      router.push({ path: redirect, query: otherQueryParams });
    });
  }
}

let time: null | number = null;
const isExpire = ref(false);
// 清除定时器
function handleClearTime() {
  if (intervalCheck) {
    clearInterval(intervalCheck);
    intervalCheck = null;
  }
  if (time) {
    clearTimeout(time);
    time = null;
  }
}
// 超时
function handleTimeout() {
  handleClearTime();
  time = setTimeout(() => {
    handleClearTime();
    isExpire.value = true;
  }, vueMetaEnv.APP_TIMEOUT);
}

// 注册跳转
function handleRegister() {
  router.push({ path: "/register" });
}

// 忘记密码
const forgotPwdVisible = ref(false);

/**
 * 根据屏幕宽度切换设备模式
 */
const appStore = useAppStore();
const WIDTH = 992; // 响应式布局容器固定宽度  大屏（>=1200px） 中屏（>=992px） 小屏（>=768px）
const { width } = useWindowSize();
watchEffect(() => {
  if (width.value < WIDTH) {
    appStore.toggleDevice("mobile");
  } else {
    appStore.toggleDevice("desktop");
  }
});
</script>

<style lang="scss" scoped>
.login-container {
  width: 100vw;
  height: 100vh;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: url(@/assets/images/login-bg.jpg) no-repeat bottom right;
  background-size: 100%;

  .mobile {
    display: none;
  }

  .desktop {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 20px;
    text-align: center;
    font-size: 14px;
  }

  .bg-small {
    width: 40%;
    height: 100%;
    left: 8%;
    position: absolute;
    font-size: 36px;
    font-weight: bold;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    > img {
      display: block;
      width: 100%;
      margin-top: 30px;
    }
  }
}

.qrcode-container {
  width: 240px;
  height: 240px;
  position: relative;
  img {
    width: 100%;
    height: 100%;
  }
  > div {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    inset: 0;
    z-index: 1;

    :last-child {
      cursor: pointer;
      color: var(--el-color-primary);
      margin-left: 10px;
    }
  }
}

:deep(.el-card__body) {
  padding: 40px 30px;
  background-color: #fff;
}

:deep(.el-card[device="desktop"]) {
  margin-right: 150px;
  margin-left: auto;
}

:deep(.el-input) {
  .el-input__inner {
    --el-input-inner-height: 40px;
    box-shadow: inset 0 0 0 40px #fff !important;
  }
}

:deep(.el-button) {
  height: 40px;
}

:deep(#pane-qrCode) {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;

  img {
    width: 240px;
  }
}

.register-btn {
  margin-top: 18px;
  font-size: 14px;
  color: #409eff;
  text-align: center;
}
</style>
